<?php defined('SYSPATH') or die('No direct access allowed.');
/**
 * Latent Semantic Indexing (LSI) is an indexing and retrieval method that uses 
 * a mathematical technique called Singular value decomposition (SVD) to identify 
 * patterns in the relationships between the terms and concepts contained in an 
 * unstructured collection of text. LSI is based on the principle that words that 
 * are used in the same contexts tend to have similar meanings. A key feature of 
 * LSI is its ability to extract the conceptual content of a body of text by 
 * establishing associations between those terms that occur in similar contexts.
 *
 * @package    DEC/LSI
 * @author     DEC Web Solutions
 * @copyright  (c) 2011 DEC Web Solutions
 * @license    http://www.apache.org/licenses/LICENSE-2.0
 */
abstract class DEC_LSI {
	
	public static $instances = array();
	private $context = "text";
	
	public function __construct($context = null) {
		if(null!=$context) $this->context = $context;
		self::$instances[$this->context] = $this;
	}
	/** 
	 * given a context, this function return an instance in this context
	 *
	 * @param string $context The context where the text is being used
	 *
	 * @return DEC_LSI
	 */
	public static function instance($context = null){
		if(null!=$context){
			if(isset(self::$instances[$context])) return self::$instances[$context];
			return new LSI($context);
		}
		if(sizeof(self::$instances)) return self::$instances[0];
		return new LSI();
	}
	/** 
	 * given a text and a context, this function return the most indicated category 
	 * to put this text in, considering a context
	 *
	 * @param string $text The text string to be categorized
	 * 
	 * @param string $context The context where the text is being used
	 *
	 * @return integer positive to id_category, 0 for no match
	 */
	public function categorize($text) {
		
		$tokens = self::tokenize($text);
		
		$tokensEscaped = array();
		foreach($tokens as $token) $tokensEscaped[] = mysql_real_escape_string($token);
		$tokenKey = implode("','", $tokensEscaped);
		
		$word = ORM::factory('word');
		$sumCount = $word->getSumCount($tokenKey, $idLsiContext);
		if($sumCount == NULL || $sumCount == 0){
			throw new Kohana_Exception("Cannot categorize \":text\" in context \":context\"", array(':text'=>$text, ':context'=>$context));
		}
		return $word->getCategory($tokenKey, $idLsiContext, $sumCount);
	}
	
	/** 
	 * given a text, and a minimun valid lenght this function return an array of
	 * valid tokens (words)
	 *
	 * @param string $text The text string to be tokenized
	 *
	 * @param integer $minLenght The minimum lenght to be accepted as a valid token
	 * @default 4
	 *
	 * @return mixed array of tokens
	 */
	private static function tokenize($text, $min_lenght = 4){
		$tokens = array();
		$strlower = array(
			"Á"=>"á",
			"É"=>"é",
			"Í"=>"í",
			"Ó"=>"ó",
			"Ú"=>"ú",
			"Ã"=>"ã",
			"Õ"=>"õ",
			"Ê"=>"ê",
			"Ô"=>"ô",
			"Â"=>"â",
			"Ç"=>"ç",
			"Ü"=>"ü",
			);
		$pattern = "/((['a-záéíóúãõêôâçü\-_]){".$min_lenght.",30}\s*)/i";
		$preg_results = array();
		if (preg_match_all($pattern, strtolower(strtr($text,$strlower)), $preg_results)) {
			foreach ($preg_results[0] as $word) {
				$tokens[] = mysql_real_escape_string((trim($word)));
			}
		}
		return $tokens;
	}
	
	/** 
	 * given a category, a text and a context, it will try to populate or increment usage
	 * of the text tokens on words and link and increment usage of within the
	 * given category id considering a context
	 * 
	 * @param integer $category_id The category to populate
	 * 
	 * @param string $text Text to be populated
	 * 
	 * @return void
	 */
	public function populate($category_id, $text) {
		$tokens = self::tokenize($text);
		print_r($tokens);
		foreach ($tokens as $token) {
			echo(PHP_EOL.$token.":");
			$word = new Model_LSI_Word($token, $this->context);
			$word->count++;
			$word->save();
			print_r($word);
			echo("($token,$this->context,$category_id)".PHP_EOL);
			$category = new Model_LSI_Category($token,$this->context,$category_id);
			$category->count++;
			$category->save();
		}
	}
}